﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MinistryStandardPlatformBusiness.Helper;
using MinistryStandardPlatformBusiness.MessagePool.Entity;
using MinistryStandardPlatformBusiness.MessagePool.QueueSession;
using System.Timers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MinistryStandardPlatformBusiness.MessagePool
{
    public class PubEventArgs : EventArgs
    {
        public string type;
        public string sim;
        public string body;
        public PubEventArgs()
        {

        }

        public PubEventArgs(string mtype, string msim, string msghb)
        {
            this.type = mtype;
            this.sim = msim;
            this.body = msghb;
        }
    }

    /// <summary>
    /// 指令
    /// </summary>
    public class Instruction
    {
        public static int TrySendTime=3; //尝试发送的方式
        public string InsId { get; set; }
        public string InsType { get; set; }
        public string Sim { get; set; }
        public string Reply { get; set; }
        public bool Expired { get; set; }
        public JObject InsBody { get; set; }
        public Timer pubTimer{ get; set; }

        private MessagePublish msgPub;
        private int sendedTime;

        public Instruction()
        {
            Reply = string.Empty;
            sendedTime=0;
            Expired = false;
        }

        public Instruction(MessagePublish _msgPub)
        {
            Reply = string.Empty;
            sendedTime=0;
            msgPub = _msgPub;
            Expired = false;
        }

        public override string ToString()
        {
 	         return InsId+","+InsType+","+InsBody.ToString()+","+Sim+";";
        }

        public void StartPublish()
        {
            pubTimer=new Timer(20*1000); //20s发送一次，直到成功
            pubTimer.Elapsed+=new ElapsedEventHandler(publish);
            pubTimer.AutoReset=true;
            pubTimer.Enabled=true;
            publish(null,null);
       
        }

        public void StopPublish()
        {
            pubTimer.Stop();
            Expired = true;
        }

        private void publish(object sender,System.Timers.ElapsedEventArgs e)
        {
            if (sendedTime == TrySendTime && (Reply == string.Empty || Reply!="0"))  //已经达到尝试发送的次数，并且还没收到应答或应答结果不是成功则放弃发送，判定为失败
            {
                //通知客户端发送失败
                StopPublish();

                JObject gpsBasic = new JObject();
                gpsBasic.Add("cmd", InsType);
                gpsBasic.Add("sim", Sim);
                gpsBasic.Add("result", Reply);

                JObject insReply = new JObject();
                insReply.Add("gType", "ins");
                insReply.Add("gpsBasic", gpsBasic.ToString());

                Log.WriteLog("Publish_Ins", InsId + "Failed(" + DateTime.Now.ToString() + ")");
                msgPub.startToPublish("ins", Sim, insReply.ToString());
                return;
            }


            if (sendedTime < TrySendTime)
            {
                try
                {
                    ++sendedTime;
                    msgPub.startToBusinessPublish("ins", Sim, InsBody.ToString());
                    Log.WriteLog("Publish_Ins", InsId+"("+DateTime.Now.ToString()+")");
                }
                catch (Exception)
                {
                    Log.WriteLog("Publish_InsError", InsBody.ToString());
                }
            }
        }

    }

    public class MessagePublish
    {

        public delegate void PublishEventHander(object sender, PubEventArgs e);
        public event PublishEventHander Publish;//web客户端推送事件
        public event PublishEventHander businessPublish;//web发送到业务中心事件

        private Dictionary<string,Instruction> InsQueue = new Dictionary<string,Instruction>();

        /// <summary>
        /// 接收来至业务中心的消息
        /// </summary>
        /// <param name="objStr"></param>
        public void RecieveMsg(string objStr)
        {
            if (objStr == "" || objStr == null || objStr == "\0")
            {
                Log.WriteLog("gpsLocationNull", ":" + objStr);
            }
            else
            {
                JObject jo = JObject.Parse(objStr);
                string type = "";
                try
                {
                    type = jo["gType"].ToString().ToLower();
                    Log.WriteLog("gpsLocation", ":" + objStr);
                }
                catch (Exception e)
                {
                    Log.WriteLog("gpsLocationError", ":" + e.ToString());
                }
                switch (type)
                {
                    case "gpslocation":
                        #region//2014/06/23 优化成task并行处理
                        System.Threading.Tasks.Task gpsTask = new System.Threading.Tasks.Task(() =>
                        {
                            LatestGpsInfo lgi = new LatestGpsInfo();
                            lgi = JsonHelper.DeserializeLatestGpsInfo(jo["gpsBasic"].ToString());

                            //更新实时信息的缓存
                            string SelStr = LatestGpsInfoHander(lgi);


                            JObject sjo = new JObject();
                            sjo.Add("gType", jo["gType"].ToString());
                            sjo.Add("gpsBasic", SelStr);
                            if (SelStr.Equals("error"))
                            {
                                Log.WriteLog("LatestGpsInfoHanderError", ":" + sjo.ToString());
                            }
                            else
                            {
                                startToPublish(type, lgi.SimId, sjo.ToString());
                            }
                        });
                        gpsTask.Start();
                        //Log.WriteLog("gpsLocation", ":" + objStr);
                        #endregion
                        break;
                    case "ins":
                        //处理来至业务中心的指令回复
                        System.Threading.Tasks.Task insTask = new Task(() =>
                        {
                            JObject sjo = new JObject();
                            sjo.Add("gType", type);
                            sjo.Add("gpsBasic", objStr);

                            JObject jo1=JObject.Parse(objStr);
                            string result=jo1["gpsBasic"]["result"].ToString();
                            string insId = jo1["gpsBasic"]["cmd"].ToString() + "-" + jo1["gpsBasic"]["sim"].ToString();
                            Log.WriteLog("MsgFromBusiness_InsReply", insId + "," + result);
                            
                            //返回结果不是失败，不再重传,将指令从指令队列中删除并返回给客户端结果
                            if (result != "1")
                            {
                                InsQueue[insId].StopPublish();
                                InsQueue.Remove(insId);
                                startToPublish(type, jo1["gpsBasic"]["sim"].ToString(), sjo.ToString());
                            }
                            
                        });
                        insTask.Start();
                        break;
                    case "gpswarn":
                        #region  //处理来自业务中心的报警信息
                        System.Threading.Tasks.Task gpswarnTask = new Task(() =>
                        {
                            GpsWarn gp = new GpsWarn();
                            gp = JsonHelper.DeserializeGpsWarn(jo["gpsBasic"].ToString());
                            if (gp.SimId != null && gp.SimId != "")
                            {
                                LngLatPoi llp = new LngLatPoi();
                                llp = TransGeoPoiHander(gp.Longitude, gp.Latitude, "1");
                                gp.NLatitude = llp.lat;
                                gp.NLongitude = llp.lng;
                                gp.Poi = llp.poi;//处理纠偏及地理位置解析
                                JObject sjo = new JObject();
                                sjo.Add("gType", jo["gType"].ToString());
                                sjo.Add("gpsBasic", JsonConvert.SerializeObject(gp));
                                startToPublish(type, gp.SimId, sjo.ToString());
                            }
                            else
                            {
                                Log.WriteLog("gpsWarnHanderError", objStr);
                            }

                        });
                        gpswarnTask.Start();
                        break;
                        #endregion
                    default:
                        System.Threading.Tasks.Task gpsunkownTask = new Task(() =>
                        {
                            startToPublish(type, "", objStr);
                        });
                        gpsunkownTask.Start();                        
                        Log.WriteLog("unkowntype", ":" + objStr);
                        break;
                }
            }
        }
        public static LngLatPoi TransGeoPoiHander(string lng, string lat, string flag)
        {
            LngLatPoi tempLngLatPoi = new LngLatPoi();
            using (DBService.DBHelperClient geoHelper = new DBService.DBHelperClient())
            {
                string LngLatPoiStr = geoHelper.GgpsTranslate2Baidu(lng, lat, "1");
                if (LngLatPoiStr.ToLower().Equals("error"))
                {
                    tempLngLatPoi.lng = lng;
                    tempLngLatPoi.lat = lat;
                }
                else
                {
                    tempLngLatPoi = JsonConvert.DeserializeObject<LngLatPoi>(LngLatPoiStr);
                }
            }
            return tempLngLatPoi;
        }
        /// <summary>
        /// 接收客户端的数据的处理
        /// </summary>
        /// <param name="objStr"></param>
        public string HeartMsgFromClientHander(string objStr)
        {
            string reStr = "0";

            if (objStr == "" || objStr == null)
                return "0";
            JObject jo = JObject.Parse(objStr);
            string type = "";
            try
            {
                type = jo["GType"].ToString().ToLower();
            }
            catch (Exception)
            {
                reStr = "0";
                Log.WriteLog("HeartMsgFromClientHander", ":" + objStr);
            }
            switch (type)
            {
                case "heart":
                    #region //在线用户维护
                    System.Threading.Tasks.Task msgTask = new System.Threading.Tasks.Task(() =>
                    {
                        try
                        {
                            UserSession.onLineUserHanderForJson(jo["GpsBasic"].ToString());
                        }
                        catch (Exception)
                        {
                            Log.WriteLog("HeartMsgFromClientHander_HeartError", jo.ToString());
                        }
                    });
                    msgTask.Start();//changed 2014/06/23
                    reStr = "1";//设置返回标识
                    break;
                    #endregion
                case "register":
                    #region//处理并响应数据
                    try
                    {
                        reStr = UserSession.registerHander(jo["GpsBasic"].ToString());//设置返回标识
                    }
                    catch (Exception)
                    {
                        reStr = "0";
                        Log.WriteLog("HeartMsgFromClientHander_RegisterError", jo.ToString());
                    }
                    break;
                    #endregion
                case "ins":
                    #region//指令消息处理,扩展位存储sim号

                    //遍历指令队列，去掉指令队列中已经过期（超过发送次数仍未发送成功）的指令并使同一条指令不能重新发送
                    string sim = jo["GpsAttatch"].ToString();
                    string cmd = jo["GpsBasic"]["cmd"].ToString();
                    bool isInsExist = false;
                    for (int i = InsQueue.Count - 1; i >= 0; i--)
                    {
                        if (InsQueue.ElementAt(i).Value.Expired)
                        {
                            InsQueue.Remove(InsQueue.ElementAt(i).Key);
                        }
                        if (InsQueue.ElementAt(i).Value.Sim == sim && InsQueue.ElementAt(i).Value.InsType==cmd)
                        {
                            isInsExist = true;
                            Log.WriteLog("HeartMsgFromClientHander_Ins", InsQueue.ElementAt(i).Value.InsId+",existed");
                        }
                    }
                    if (!isInsExist)
                    {
                        reStr = "2";
                        System.Threading.Tasks.Task insTask = new Task(() =>
                        {
                            try
                            {

                                JObject sjo = new JObject();
                                sjo.Add("gType", "gpsCommand");
                                sjo.Add("gpsBasic", jo["GpsBasic"].ToString());
                                //组装发送至业务中心的数据

                                Instruction ins = new Instruction(this);
                                ins.Sim = jo["GpsAttatch"].ToString();
                                ins.InsBody = sjo;
                                ins.InsType = jo["GpsBasic"]["cmd"].ToString();
                                ins.InsId = jo["GpsBasic"]["cmd"].ToString() + "-" + jo["GpsBasic"]["GpsAttatch"].ToString();

                                InsQueue.Add(ins.InsId, ins);
                                Log.WriteLog("HeartMsgFromClientHander_Ins", ins.ToString());
                                ins.StartPublish();

                                //startToBusinessPublish(type, jo["GpsAttatch"].ToString(), sjo.ToString());
                            }
                            catch (Exception)
                            {
                                Log.WriteLog("HeartMsgFromClientHander_InsError", jo.ToString());
                            }

                        });
                        insTask.Start();
                    }
                    else
                    {
                        reStr = "1";
                    }
                    break;
                    #endregion
                case "celllocation":
                    #region 基站定位请求
                    System.Threading.Tasks.Task cellLocationTask = new Task(() =>
                    {
                        try
                        {
                            JObject sjo = new JObject();
                            sjo.Add("gType", "cellLocation");
                            sjo.Add("gpsBasic", jo["GpsBasic"].ToString());
                            //组装发送至业务中心的数据
                            startToBusinessPublish(type, jo["GpsAttatch"].ToString(), sjo.ToString());
                        }
                        catch (Exception)
                        {
                            Log.WriteLog("HeartMsgFromClientHander_cellLocationError", jo.ToString());
                        }

                    });
                    cellLocationTask.Start();
                    reStr = "1";//基站定位消息分发成功返回1
                    break;
                    #endregion
                case "gpsApp":
                    #region 终端信息更改
                    System.Threading.Tasks.Task gpsAppTask = new Task(() =>
                    {
                        try
                        {
                            JObject sjo = new JObject();
                            sjo.Add("gType", "gpsApp");
                            sjo.Add("gpsBasic", jo["GpsBasic"].ToString());
                            //组装发送至业务中心的数据
                            startToBusinessPublish(type, jo["GpsAttatch"].ToString(), sjo.ToString());
                        }
                        catch (Exception)
                        {
                            Log.WriteLog("HeartMsgFromClientHander_gpsAppError", jo.ToString());
                        }
                    });
                    gpsAppTask.Start();
                    reStr = "1";
                    break;
                    #endregion
                default:
                    Log.WriteLog("unkowntype", ":" + objStr);
                    reStr = "1";//设置返回标识
                    break;
            }
            return reStr;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="lgi"></param>
        /// <returns>更新成功:返回true 更新失败:返回false</returns>
        private string LatestGpsInfoHander(LatestGpsInfo lgi)
        {
            LngLatPoi mLngLatPoi = new LngLatPoi();

            if (lgi != null && lgi.SimId != null)
            {
                //地理解析
                if (string.IsNullOrEmpty(lgi.Memo))
                {
                    mLngLatPoi = TransGeoPoiHander(lgi.Longitude, lgi.Latitude, "1");
                    lgi.Nlongitude = mLngLatPoi.lng;//纠偏后的经度 百度坐标
                    lgi.Nlatitude = mLngLatPoi.lat;//纠偏后的纬度  百度坐标
                    lgi.Poi = mLngLatPoi.poi;
                }
                else
                {
                    lgi.Poi = lgi.Memo;
                }

                try
                {//维护实时信息
                    if (lgi != null && lgi.IsValid())
                    {
                        if (UserSession.LatestGpsInfoDic.ContainsKey(lgi.SimId))
                        {
                            UserSession.LatestGpsInfoDic[lgi.SimId] = lgi;
                            Log.WriteLog("UpdateLatestGpsInfo", JsonConvert.SerializeObject(lgi));
                        }
                        else
                        {
                            UserSession.LatestGpsInfoDic.Add(lgi.SimId, lgi);
                            Log.WriteLog("AddLatestGpsInfo", JsonConvert.SerializeObject(lgi));
                        }
                    }
                }
                catch (Exception)
                {
                    Log.WriteLog("LatestGpsInfoHanderError", JsonConvert.SerializeObject(lgi));

                    return "error";
                }

            }

            return JsonConvert.SerializeObject(lgi);
        }

        #region web publishhander
        public void startToPublish(string mtype, string msim, string mbody)
        {
            if (mtype != null && msim != null && mbody != null)
            {
                OnPublish(new PubEventArgs(mtype, msim, mbody));
            }
        }
        private void OnPublish(PubEventArgs e)
        {
            if (Publish != null)
            {
                this.Publish(this, e);
            }
        }
        #endregion
        #region business publish
        public void startToBusinessPublish(string mtype, string msim, string mbody)
        {
            if (mtype != null && msim != null && mbody != null)
            {
                OnToBusniss(new PubEventArgs(mtype, msim, mbody));
            }
        }

        private void OnToBusniss(PubEventArgs e)
        {
            if (businessPublish != null)
            {
                this.businessPublish(this, e);
            }
        }
        #endregion
    }
}
